What's new ========== This page records user-visible changes to the RISE Toolbox -- new features, behaviour changes, and things you may need to know when upgrading. Newest entries go on top. .. note:: This log is being (re)started together with the documentation overhaul. It is not yet exhaustive of the toolbox's full history; older changes are summarised in passing where relevant. Current release --------------- - **New** ``rise.microfound`` **-- write the economics, not the algebra.** A model *definition* builder: declare the atoms and each agent's optimization problem (period objective, choice variables, named constraints) in MATLAB, and RISE derives the first-order conditions symbolically and generates a plain RISE model -- no ``@optimization_problem`` block, nothing hidden. Hand the builder to ``dsge_model`` directly, as a cell array via ``code(p)``, or as a written ``.rs`` file via ``rs(p,file)``; calibration and solving remain ``dsge_model``'s job. Derived Lagrange multipliers are named ``_lambda_`` and every generated equation is tagged with its origin. Switching parameters in an agent's problem yield the correct probability-weighted switching FOCs automatically -- a capability gEcon lacks. Validated by re-authoring nine gEcon example models. Heterogeneous-agent (HANK) support is a planned extension. See :doc:`../DSGE_capabilities/Microfoundations/Deriving models with microfound`. - **Leads greater than one are reduced without violating Jensen's inequality.** When you write a variable two or more periods ahead, RISE rewrites the model so that no equation carries a lead greater than one. Terms that are *nonlinear* in a forward variable (e.g. ``exp(x{+2})``) are now wrapped in an auxiliary carrying the whole term's one-period-ahead conditional expectation, so ``E[g(x)]`` is preserved rather than collapsed to ``g(E[x])``; *affine* leads (a constant-weighted sum such as ``0.08*V{+2}``) use the ordinary atomic chain. This matters only beyond first order -- at first order and under perfect foresight there is certainty equivalence and the wrapping is inert. Every auxiliary keeps a contemporaneous variable, so the contemporaneous matrix ``A0`` stays non-singular and iterative solvers (cyclic reduction, the ``mfi`` optimal-policy iteration) still apply. The old ``violate_jensen_inequality`` option and its whole-equation backshift alternative have been **removed**: there is now a single, always-correct reduction, and linear models and derived optimal-policy first-order conditions are reduced exactly as before. A note deriving the effect in closed form (including where the ``sigma^2`` term comes from) ships under ``development/jensen_memo``. - **New ``get(m,'options')``.** Returns a model's current settable options and their values -- the get-side companion to ``set``. Handy for inspecting what a model is actually configured with. - **Model objects now record the RISE version that built and estimated them.** Every constructed model carries a provenance stamp, queryable with ``get(m,'rise_version')`` -- a struct with fields ``construction`` (the version that parsed/built the object) and ``estimation`` (the version that ran ``estimate``, ``''`` until the model is estimated). The shortcuts ``get(m,'construction_version')`` and ``get(m,'estimation_version')`` return the individual strings, and ``summary(m)`` now prints a *Built with RISE* / *Estimated with RISE* line. The stamps are frozen into the object and survive a ``saveObj``/``loadObj`` round-trip, so a model built under one version and estimated under a later one reports both faithfully. This is distinct from ``rise.version``, which reports the *currently installed* toolbox. Objects saved before this change load unchanged and report ``''`` (unknown) for the missing stamps. - **MCMC correctness: independence Metropolis-Hastings and DRAM fixed.** Two procedural defects in the samplers were corrected: - The **independence sampler** drew its proposal as a random walk centered on the *current state* rather than from the fixed proposal distribution, while the acceptance applied the independence-sampler density correction -- so the chain targeted ``pi(x)/q(x)`` instead of ``pi(x)``. It now draws from the fixed distribution. (Note: tuning an independence sampler to a fixed random-walk acceptance target such as 0.234 is not meaningful -- its acceptance is governed by how well the fixed proposal matches the target.) - The **delayed-rejection (DRAM)** second-stage acceptance omitted the ``1/adascale^2`` scaling of the first-stage proposal covariance in its proposal-density ratio, biasing the second-stage acceptance whenever ``adascale ~= 1`` (the default ``2.38/sqrt(d)``). - **Posterior density plots: complex-valued bivariate kernel density fixed.** The multivariate kernel-density bandwidth used a matrix square root ``cov(X)^0.5`` that turned complex when the sample covariance of near-degenerate draws acquired a tiny negative eigenvalue from roundoff, making the whole density complex and breaking ``surf``/``mesh``. It now uses a real symmetric positive-definite square root -- identical to the old value when the covariance is well conditioned, real and finite when it is not. - **set: combined optimal-policy options no longer silently dropped (MPE + discretion).** The internal slot that pushes the special policy parameters (``ole``, ``commitment``) was a scalar struct overwritten on each match, so passing both ``solve_policy_equilibrium`` and ``solve_policy_type`` in a single ``set``/``solve`` call dropped one of them -- ``MPE`` + ``discretion`` actually ran ``OLE`` + ``discretion``. The slot now accumulates its entries, so combined optimal-policy option pushes are all honored. - **Unified predict-step for filtering: OBC anticipation and observed expectations now share one code path.** Two long-standing gaps in the filtering layer have been closed, in the same surgical edit to a single shared predict-step closure: - **Filtering under OBC with an anticipation horizon.** With ``solve_shock_horizon > 0`` on a model that declares ``simul_constraints``, the filter's predict step now runs a constraint-aware multi-step forecast across the full ``k+1`` anticipation window via ``obcas.optim.forecast_with_constraints``, and keeps only the one-step-ahead result. The previous fast path (one-step unconstrained, then check, then optionally invoke the complementarity engine) is preserved bit-identical for the no-anticipation case (``shock_horizon == 0``), so locked filtering baselines on OBC models do not move. - **Filtering with observed expectations.** Multi-page conditional data (``forecast_cond_endo_vars`` set, ``ts`` observables with more than one page so each ``t`` carries observed values for ``t+1, t+2, ...``) now enters the same multi-step solve as equality restrictions. The previous dispatch to ``msre_kalman_cell_real_time`` was broken: that function had been moved into ``+archive/`` and was no longer on the MATLAB path, so any user calling ``filter`` on a model with ``forecast_cond_endo_vars`` and multi-page data hit an undefined-function error. The dispatch is removed; the regular regime-switching Kalman filter handles real-time conditioning natively by handing per-``t`` target values into the predict-step closure, which pre-fills them at the ``t+1`` slot of the multi-step forecast array and lets ``obcas.optim.forecast_with_constraints`` solve for the stochastic shocks that satisfy them. Both cases use the same gating: when an anticipation horizon is active or per-``t`` conditioning targets are supplied, the predict step routes through the multi-step solver; when neither is active it falls through to the fast path. New ``cpf`` auto-route gate also excludes any non-zero shock-horizon model so the wrapped constant-parameter filter is not selected on models whose impact matrix is 3-D. - **Documentation build no longer leaves a dated PDF backup.** Previously every successful ``update_documentation.m`` run renamed ``help/risetoolbox.pdf`` to ``help/risetoolbox .pdf`` before the new PDF was copied in, as a defensive fallback against bad builds. In practice it just cluttered ``help/`` and the repo with dated copies. The fallback has been removed; ``copyfile`` overwrites in place, and bad builds can be reverted via git like any other commit. - **bvar_dsge estimation: fixed regression introduced by the @epilogue auto-append work.** The recent rewiring of ``@transition_functions`` / ``@epilogue`` into every output engine (see the entry below) introduced a method-dispatch failure on the bvar_dsge likelihood path. The bvar_dsge solver leaves its internal dsge representation in struct form (rather than as a ``@dsge`` object), and the added call to ``append_epilogue`` inside the Kalman save-filters step then could not resolve. The runtime evaluator has been moved out of ``@dsge`` into the ``dsge_tools.epilogue`` namespace so it dispatches uniformly on either representation. No change to user-facing API; bvar_dsge ``estimate``, ``filter``, ``forecast`` and ``mode_curvature`` go through the standard paths again. - **sstate_endo_param_swap: target values now preserved to full double precision.** The internal constraint equation built from a ``sstate_endo_param_swap = {endogName, value, paramName}`` triple was rendered with ``sprintf('%g', value)``, which truncates to six significant digits. For irrational targets such as ``log(1/3)``, this baked a ~2e-6 rounding error directly into the residual the solver was driving to zero. The render now uses ``%.17g`` (round-trip precision for IEEE-754 doubles), so constraints with ``log``, ``exp``, ``pi`` and similar transcendental targets solve to machine precision again. - **@transition_functions and @epilogue: fully wired into all output paths.** Time-varying transition probabilities and post-solve derived series declared in ``@transition_functions`` / ``@epilogue`` blocks now appear automatically on the output of every engine that produces a simulated ``ts`` database: ``simulate``, ``irf``, ``forecast``, ``filter``, ``perfect_foresight``, ``counterfactual``, ``resimulate``, and ``brute_force_simulate``. Previously only ``simulate`` / ``irf`` / ``forecast`` (which share a common engine) auto-appended them; users on the other paths saw the series silently missing and had to call ``obj.append_epilogue(db)`` by hand. Also fixed in the same round: - **Switching parameters now follow the realised regime path.** A switching parameter referenced on the RHS of an ``@epilogue`` or ``@transition_functions`` equation used to take its regime-1 value everywhere — wrong whenever the realised regime trajectory included other regimes. The runtime now builds a ``ts`` indexed by ``db.regime`` for switching parameters, so the value at each period follows the realised path. Const-chain parameters are unchanged. - **#-definitions are usable on the RHS.** A ``#``-definition like ``# mid_p = (p_lo + p_hi)/2;`` can now be referenced by its bare name inside a ``@transition_functions`` or ``@epilogue`` equation; previously the name was left unbound and the runtime crashed on first call. - **Multiple ``@transition_functions`` / ``@epilogue`` blocks** in the same model file are stitched together — you can split a chain's two probabilities across two blocks or interleave them with other declarations. - **Perfect-foresight solver: faster and more robust.** The deterministic `perfect_foresight` solver gained several improvements, all behaviour-preserving at their defaults (see :doc:`../DSGE_capabilities/Deterministic/Deterministic and quasi-deterministic solutions`): - the default ``'sparse'`` solver now judges convergence on the **max-abs** (infinity-norm) residual rather than the 2-norm. The 2-norm of a stacked residual grows like :math:`\sqrt{T\times\text{endo\_nbr}}`, so a fixed tolerance was unreachable for long horizons even when every equation residual was tiny; the max-abs criterion is per-equation and size-independent. - a new **JacobianUpdate** option on the ``'sparse'`` solver enables modified-Newton **factorization reuse**: factorize the stacked Jacobian once and reuse the LU factors (``inf``), or refresh every ``K`` iterations; ``1`` (default) is full Newton. On transition problems this leaves the solution unchanged while substantially cutting the time in the linear solve. - a new **simul_reuse_sstate** option (default ``false``) skips the internal steady-state re-solve when the model is already solved -- for pre-solved / repeated / extended-path runs. - **Steady-state solve: false "could not solve" failures fixed.** The steady-state success verdict compared the residual against the solver's iterate tolerance (``sqrt(eps)``), which sits right at the achievable residual floor, so well-converged solutions on some models (e.g. the canonical ``ramst``) were falsely reported as failures. The acceptance verdict is now decoupled from the solver tolerance via a floor, judged on the max-abs residual; achieved precision is unchanged. The engine also refreshes the parameter/definition values on every solve, so parameter changes (estimation, calibration) propagate correctly into the steady state. - **Non-cooperative games: Markov-perfect equilibrium (MPE) as a solve-time option.** Optimal-policy models that declare more than one policymaker (Nash or Stackelberg) now expose a second equilibrium concept alongside the historical open-loop equilibrium (OLE):: m = solve(m, 'solve_policy_equilibrium', 'OLE'); % default m = solve(m, 'solve_policy_equilibrium', 'MPE'); Under OLE each player optimises against the opponent's *path*; under MPE each player optimises against the opponent's *policy function*. For single-player models MPE and OLE coincide (Proposition 3); for multi-player Nash on the standard benchmark, the gap matches the theoretical reference. Internally the MPE branch adds a small cross-player chain-rule term to each predetermined-state FOC row -- no new endogenous variables, the augmented system has the same size as the OLE-only system, and at the default ``solve_policy_equilibrium='OLE'`` results are byte-identical to releases that did not have the option. See :doc:`../DSGE_capabilities/OptimalPolicy/Optimal Policy` for the conceptual details and the small restrictions (stochastic replanning rejects the option; ``@no_u_turn = true`` makes the MPE addition a no-op). - **Very large models now parse end-to-end.** Models with thousands of equations that previously could not be loaded by ``rise(...)`` at all (notably the ``marco.rs`` / "very large quest" model used internally) now parse in roughly three minutes on a desktop machine. The fix removed several O(n^2)-in-#equations hotspots in the post-``parse_model`` pipeline (``shadowize_engine``, ``occurrences``, ``regexpmatch``, ``update_leads_and_lags``, ``create_functions``, ``initialize_symbols``, ``stamper.status``), switched ``rsymbdiff.occurrence`` from a dense ``1 x nwrt`` logical mask to a sorted index list (peak memory on the same model dropped from ~9.6 GB to ~4.6 GB), and broke the reference cycle in the symbolic-differentiation CSE backend that used to keep MATLAB's cycle-collector busy for tens of minutes at workspace teardown. The validation suite (``model_creation``, ``modeling_language``, ``optimal_policy``, ``steadyState``, ``loglinear``, ``solvers_generic``, ``perturbation``, ``dynare``) passes with no regressions. - **Reporting figure x-axis fixed.** Figures produced through ``rprt.create_figure`` with highlighted date ranges (e.g. ``highlighted_dates``) were rendering with the data crushed into a thin strip at the left edge of the plot and the x-axis extending to year ~4016. Cause: ``fill`` was receiving ``rise_dates.dates`` values that MATLAB silently downcast to ``datenum`` against a ``datetime`` axis. The highlight band is now converted to ``datetime`` before being passed to ``fill``, so the patch lands in the same coordinate system as the line plot and ``xlim`` stays at the real data range. - **Progress monitor: explicit close handle.** ``progress_monitor`` now returns a fourth optional output, a function handle that tears down the GUI window (and tidies up the cancel-flag file) on demand. The built-in auto-close still fires when every chain reaches its announced iteration count; the new handle covers the case where the work terminates early (``MaxTime`` / ``MaxFunEvals`` / an exception in one chain), where the auto-close condition would never have held and the GUI used to orphan. - **``@log_variables`` / ``@level_variables`` are deprecated.** The recommended way to declare log-approximated variables is the inline ``@endogenous(log)`` form (with ``@endogenous(log_vars)`` and ``@endogenous(log_variables)`` as accepted aliases). The legacy block-level keywords ``@log_variables``, ``@log_vars`` and ``@level_variables`` (with the ``@all_but`` complement) are still parsed for backwards compatibility but the documentation now flags them as deprecated. The two styles cannot be mixed inside the same model file. - **Time series indexing overhaul (partial break).** The :ref:`@ts ` class now distinguishes ``()`` and ``{}`` the same way built-in ``table`` and ``timetable`` do: ``db(...)`` returns a sub-time-series, ``db{...}`` returns the raw numeric block. ``db.VARNAME`` returns the corresponding single-variable ts when the name is not a property. The familiar ``db{-1}`` / ``db(+3)`` "time-shift" shortcut is **kept on dated time series**, where a scalar integer is unambiguous (no date has a plain numeric value) - it is equivalent to ``lag(db, 1)`` / ``lead(db, 3)`` and returns a ts (NaN-padded, same length). On **undated** time series, a scalar numeric is the implicit date value instead (``db{1990}`` on ``ts(1990, data)`` returns row 1); time shifts on undated ts require the explicit ``lag``/``lead``/``shift`` methods. Scalar-numeric **assignment** (``db{-1} = X``) is not supported in either case. See :ref:`ts-indexing` for the full contract. - **``transform`` preserves the date axis.** Period-to-period growth and difference variants (``pct_ch``, ``diff``, ``log_ch`` and their YoY cousins) now return a time series of the same length as the input, with the leading rows that have no defined past observation set to ``NaN``. The previous behaviour silently dropped those rows. - **Mixed-frequency date selection.** Indexing a quarterly time series with an annual date, e.g. ``db(ry(1991))``, now correctly returns the four quarters of 1991 (previously it returned only the closest single quarter). - **Chow-Lin temporal disaggregation works again.** ``chowlin`` had been calling a helper that no longer existed in the toolbox path; rewired on the live ``rise_dates`` API and gated on integer high-/low-frequency ratios so non-supported pairs (e.g. W->D) error cleanly. Inputs and outputs are unchanged. - **Date system polish.** ``'A'`` is now accepted as a public annual synonym for ``'Y'`` (``date2serial('1990A1')`` is equivalent to ``date2serial('1990')`` / ``ra(1990)`` / ``ry(1990)``; previously the date parser rejected ``'A'`` even though every other part of the date system already accepted it). ``is_date`` short-circuits on ``rise_dates.dates`` and finite-integer ``double`` inputs instead of going through the heavy ``try/catch`` ``date2serial`` path. ``@ts/convert.m`` now uses ``dictionary`` rather than ``containers.Map`` for its frequency-step lookups. - **MATLAB R2023b is now required.** RISE uses the ``dictionary`` / ``configureDictionary`` data type, introduced in R2023b; ``rise_startup`` checks the running release and stops with a clear error on anything older. - **Distribution and licensing.** This edition (the "Beta" edition) is shipped in compiled (p-coded) form and is distributed personally by the author; it is proprietary and not for redistribution. See :doc:`RISE License` (the full terms are also in ``LICENSE.txt``). - **The ``+rise`` package.** Housekeeping commands are grouped under the ``rise`` package: ``rise.startup`` (``rise_startup``; accepts ``quiet`` for a one-line load, and ``true`` to unload), ``rise.exit`` (``rise_exit``), ``rise.demo`` (``rise_demo`` -- installation check + a quick tour), ``rise.doc`` (opens the PDF manual), ``rise.version``, ``rise.release``, ``rise.toolbox``. See :doc:`The RISE package`. - **Refreshed start-up banner** summarising your MATLAB version, the optional toolboxes (Optimization, Statistics and Machine Learning), the LaTeX status, and where the manual lives. - **PDF reporting degrades gracefully**: if ``pdflatex`` is not on the ``PATH``, RISE still loads -- only PDF reporting is disabled, and the banner says so. - **Documentation overhaul** in progress: a corrected :doc:`Installation` page, a single-source license, this page and a :doc:`Quickstart`, with a chapter-by-chapter refresh to follow (see ``DOC_STRATEGY.md`` in the docs repository). Where the canonical changelog lives ----------------------------------- The single source of truth for release notes is now ``CHANGELOG.md`` in the toolbox root, next to ``README.md``. This page mirrors it; the two are kept in sync by the documentation build (or by hand during the transition). New entries should be added to ``CHANGELOG.md`` first, then reflected here under the appropriate section -- not the other way around. In MATLAB, the most recent entries are surfaced by ``rise.whatsnew`` (or its shortcut ``rise_whatsnew``): .. code-block:: matlab rise.whatsnew % print the entire CHANGELOG rise.whatsnew(3) % print the 3 most recent dated/Unreleased sections rise_whatsnew(1) % shortcut, same semantics The function lives at ``+rise/whatsnew.m`` in the toolbox; the shortcut at ``m/shortcuts/rise_whatsnew.m`` mirrors the pattern of ``rise_demo`` / ``rise_doc``.